﻿using HARTCalibrationTool.Commands.TwoDimensionalCMDGroup;
using HARTCalibrationTool.SerialPortManager;
using System;
using System.Collections.Generic;
using System.Drawing.Text;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HARTCalibrationTool.Commands
{
    public class LoopCMDsGroup
    {
        public Queue<(CommandsBase, TimeSpan delay)> _commandsQueue = new Queue<(CommandsBase, TimeSpan delay)>();

        public int MaxRetries { get; set; } = 3;
        public CMDsChlID CurrentGroupChl { get; private set; } = CMDsChlID.eChannelNull;

        public LoopCMDsGroup(CMDsChlID chl) 
        {
            CurrentGroupChl = chl;
        }

        public void AddCommands(IEnumerable<(CommandsBase, TimeSpan delay)> commands)
        {
            foreach (var command in commands)
            {
                _commandsQueue.Enqueue(command);
            }
        }

        public void DeleteCommands()
        {
            _commandsQueue.Clear();
        }

        public async Task ExecuteLoopGroupAsync()
        {
            SerialPortsBase serialPort = null;

            try
            {
                if ((_commandsQueue != null) && (_commandsQueue.Any()))
                {
                    foreach (var (cmd, delay) in _commandsQueue)
                    {
                        serialPort = cmd.SerialPortMager;
                        serialPort.SetCurrentCMD(cmd);
                        serialPort.CommandCompleted += OnCommandCompleted;
                        int retryCount = 0;
                        bool isSuccess = false;

                        cmd.CurrentGroupChannel = this.CurrentGroupChl;

                        while (retryCount <= MaxRetries)
                        {
                            var commandTask = cmd.ExecuteCMD();
                            var timeoutTask = Task.Delay(TimeSpan.FromSeconds(2));

                            var completedTask = await Task.WhenAny(commandTask, timeoutTask);

                            if (commandTask == timeoutTask)
                            {
                                cmd.PrintMessage("Command:" + cmd.CommandName + ", 发送超时！");

                                if (retryCount == 3)
                                {
                                    serialPort.CommandCompleted -= OnCommandCompleted;
                                    break;
                                }

                                retryCount++;
                                continue;
                            }
                            else
                            {
                                isSuccess = await WaitForResponseAsync(cmd);

                                if (isSuccess)
                                {
                                    await Task.Delay(delay);

                                    break;
                                }
                                else
                                {
                                    retryCount++;

                                    if (retryCount > MaxRetries)
                                    {
                                        cmd.OnFailure();
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch 
            { 
            
            }
        }

        private async Task<bool> WaitForResponseAsync(CommandsBase command)
        {
            var tcs = new TaskCompletionSource<bool>();
            EventHandler handler = (s, e) => tcs.TrySetResult(true);
            SerialPortsBase serialPort = command.SerialPortMager;
            bool isSuccess = false;

            try
            {
                serialPort.CommandCompleted += handler;

                var timeoutTask = Task.Delay(TimeSpan.FromSeconds(5));
                var responseTask = tcs.Task;

                var completedTask = await Task.WhenAny(responseTask, timeoutTask);

                if (completedTask == timeoutTask)
                {
                    command.OnTimeout();
                    command.PrintMessage("Command:" + command.CommandName + ", 响应超时！");
                }
                else
                {
                    command.OnSuccess();
                    isSuccess = true;
                }
            }
            catch (Exception ex)
            {
                command.PrintMessage(ex.ToString());
            }
            finally
            {
                serialPort.CommandCompleted -= handler;
            }

            return isSuccess;
        }

        private void OnCommandCompleted(object sender, EventArgs e)
        {
            // Notify that the command has completed and proceed to the next command
            //_cts?.Cancel();
        }
    }

    public class LoopGroupCMDsManager
    {
        private static LoopCMDsGroup[] _loopCMDsGroup = null;
        private static bool _isStop = false;

        static LoopGroupCMDsManager()
        {
            _loopCMDsGroup = new LoopCMDsGroup[32]
            {
                new LoopCMDsGroup(CMDsChlID.eChannel1),
                new LoopCMDsGroup(CMDsChlID.eChannel2),
                new LoopCMDsGroup(CMDsChlID.eChannel3),
                new LoopCMDsGroup(CMDsChlID.eChannel4),
                new LoopCMDsGroup(CMDsChlID.eChannel5),
                new LoopCMDsGroup(CMDsChlID.eChannel6),
                new LoopCMDsGroup(CMDsChlID.eChannel7),
                new LoopCMDsGroup(CMDsChlID.eChannel8),
                new LoopCMDsGroup(CMDsChlID.eChannel9),
                new LoopCMDsGroup(CMDsChlID.eChannel10),
                new LoopCMDsGroup(CMDsChlID.eChannel11),
                new LoopCMDsGroup(CMDsChlID.eChannel12),
                new LoopCMDsGroup(CMDsChlID.eChannel13),
                new LoopCMDsGroup(CMDsChlID.eChannel14),
                new LoopCMDsGroup(CMDsChlID.eChannel15),
                new LoopCMDsGroup(CMDsChlID.eChannel16),
                new LoopCMDsGroup(CMDsChlID.eChannel17),
                new LoopCMDsGroup(CMDsChlID.eChannel18),
                new LoopCMDsGroup(CMDsChlID.eChannel19),
                new LoopCMDsGroup(CMDsChlID.eChannel20),
                new LoopCMDsGroup(CMDsChlID.eChannel21),
                new LoopCMDsGroup(CMDsChlID.eChannel22),
                new LoopCMDsGroup(CMDsChlID.eChannel23),
                new LoopCMDsGroup(CMDsChlID.eChannel24),
                new LoopCMDsGroup(CMDsChlID.eChannel25),
                new LoopCMDsGroup(CMDsChlID.eChannel26),
                new LoopCMDsGroup(CMDsChlID.eChannel27),
                new LoopCMDsGroup(CMDsChlID.eChannel28),
                new LoopCMDsGroup(CMDsChlID.eChannel29),
                new LoopCMDsGroup(CMDsChlID.eChannel30),
                new LoopCMDsGroup(CMDsChlID.eChannel31),
                new LoopCMDsGroup(CMDsChlID.eChannel32),
            };
        }

        public LoopGroupCMDsManager()
        {
            for (int i = 0; i < 32; i++)
            {
                _loopCMDsGroup[i].DeleteCommands();
            }
        }

        public void AddCommandsByChl(int chl, IEnumerable<(CommandsBase, TimeSpan delay)> commands)
        {
            // chl = [0,31]
            _loopCMDsGroup[chl].AddCommands(commands);
        }

        public async Task ExecuteAllLoopGroupsAsync()
        {
            _isStop = false;

            while (!_isStop & true)
            {
                for (int i = 0; i < 32; i++)
                {
                    if (_isStop)
                    {
                        break;
                    }

                    if (_loopCMDsGroup[i]._commandsQueue.Count != 0)
                    {
                        SerialPortsBase.PrintMessage($"通道{i+1}复测: ");
                        await _loopCMDsGroup[i].ExecuteLoopGroupAsync();
                    }
                }
            }
        }

        public void Stop()
        { 
            _isStop = true;

            for (int i = 0; i < 32; i++)
            {
                _loopCMDsGroup[i].DeleteCommands();
            }

            SerialPortsBase.PrintMessage("复测采集停止!");
        }

        public void Resume()
        { 
            _isStop = false;
            Task.Run(() => ExecuteAllLoopGroupsAsync());
        }
    }
}
